#pragma once


#include <iostream>
#include <string>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
#include "task.hpp"
#include "daem.hpp"
#include "threadpool.hpp"
enum
{
    SOCKET_ERR = 1,
    BIND_ERR,
    LISTEN_ERR,
};

const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8080; 
const int backlog = 10;

class TcpServer;

struct ThreadData
{
    ThreadData(int sockfd, const std::string& client_ip, uint16_t client_port, TcpServer* tcpsvr)
        : _sockfd(sockfd)
        , _client_ip(client_ip)
        , _client_port(client_port)
        , _tcpsvr(tcpsvr)
    {}
    int _sockfd;
    std::string _client_ip;
    uint16_t _client_port;
    TcpServer* _tcpsvr;
};

class TcpServer
{
public:

    // static void* handler(void* argc)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData* td = static_cast<ThreadData*>(argc);
    //     td->_tcpsvr->service(td->_sockfd, td->_client_ip, td->_client_port);
    //     delete td;
    //
    //     return nullptr;
    // }


public:

    TcpServer(uint16_t port = default_port)
        : _ip(default_ip)
        , _port(default_port)
    {
    }

    void init()
    {
        // 创建套接字
        _listen_sock = socket(AF_INET, SOCK_STREAM, 0);
        if(_listen_sock < 0)
        {
            lg(Fatal, "socket error, listen_sock = %d", _listen_sock);
            exit(SOCKET_ERR);
        }
        lg(Info, "socket success, listen_sock = %d", _listen_sock);

        // 绑定套接字
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port =  htons(_port);
        local.sin_addr.s_addr = inet_addr(_ip.c_str());

        if(bind(_listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            lg(Fatal, "bind error, errno: %d, error string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind success, errno: %d, error string: %s", errno, strerror(errno));

        // tcp是面向连接的服务器， 服务器要一直处于一种等待连接的状态
        if(listen(_listen_sock, backlog) < 0)
        {
            lg(Fatal, "listen error, errno: %d, error string: %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
    }

    // void service(int sockfd, const std::string& client_ip, const uint16_t& client_port)
    // {
    //     char inbuffer[4096];
    //     while(1)
    //     {
    //         // 读取数据
    //         ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
    //         if(n > 0)
    //         {
    //             inbuffer[n] = '\0';
    //             std::cout << "client[" << client_ip << ":" << client_port << "] say# " << inbuffer << std::endl;

    //             std::string outbuffer = "server sent a message@ " + std::string(inbuffer);
    //             write(sockfd, outbuffer.c_str(), outbuffer.size());
    //         }
    //         else if(n == 0)
    //         {
    //             lg(Info, "client %s : %d quit", client_ip.c_str(), client_port);
    //             break;
    //         }
    //     }

    //     close(sockfd);
    // }

    void run()
    {
        Daemon();
        // 启动线程库创建线程
        ThreadPool<Task>* tp = ThreadPool<Task>::getThreadPool();
        tp->start();

        while(1)
        {
            // 1， 获取新链接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listen_sock, (struct sockaddr*)&client, &len);
            if(sockfd < 0)
            {
                lg(Warning, "accept error, sockfd: %d", sockfd);
                continue;
            }

            // 2,根据新链接来进行通信
            uint16_t client_port = ntohs(client.sin_port);
            char ipstr[32];
            inet_ntop(AF_INET, &(client.sin_addr), ipstr, sizeof(ipstr));
            std::string client_ip = ipstr;

            lg(Info, "client %s : %d connect", client_ip.c_str(), client_port);


            // // vertion 1 单进程
            // lg(Info, "client %s : %d connect", client_ip.c_str(), client_port);
            // service(sockfd, client_ip, client_port);

            // // vertion 2 多进程
            // lg(Info, "client %s : %d connect", client_ip.c_str(), client_port);
            // int pid = fork();
            // if(pid == 0)
            // {
            //     // child
            //     close(_listen_sock);
            //     if(fork() != 0)
            //     {
            //         // father
            //         exit(0);
            //     }
            //     // 子进程再创建孙子进程，把子进程关闭，孙子进程成为孤儿进程，交给sys，父进程等待就不会被阻塞
            //     // 或者通过信号量， 让父进程不用等待
            //     service(sockfd, client_ip, client_port);
            //     exit(0);
            // }
            // close(sockfd);
            // waitpid(pid, nullptr, 0);

            // // vertion 3 多线程
            // ThreadData* td = new ThreadData(sockfd, client_ip, client_port, this);

            // pthread_t tid;
            // pthread_create(&tid, nullptr, handler, td);

            // vertion 4 线程池
            Task t(sockfd, client_ip, client_port);
            tp->push(t);

        }
    }

    ~TcpServer()
    {
        
    }

private:
    int _listen_sock;
    std::string _ip;
    uint16_t _port;
};